package grpcmgr

import (
	"context"
	"gameserver/messages"
	"gameserver/server"
	"gameserver/server/redisutil"
	"net"

	"gitee.com/night-tc/gobige/entity"
	"gitee.com/night-tc/gobige/global"
	"gitee.com/night-tc/gobige/logger"
	"gitee.com/night-tc/gobige/msgdef"
	"gitee.com/night-tc/gobige/msgdef/protomsg"
	"gitee.com/night-tc/gobige/serverMgr"
	"gitee.com/night-tc/gobige/sess"
	"gitee.com/night-tc/gobige/threads"
	"google.golang.org/grpc"
)

type GrpcLinker struct {
	messages.UnimplementedGrpcLinkerServer
	Info       *global.ListenCfg
	GrpcServer *grpc.Server
	lister     net.Listener
	Port       int
	//链接管理器
	thgo *threads.ThreadGo
	// 服发现
	dirMgr *serverMgr.DiscoveryMgr
}

func NewGrpcNet(info *global.ListenCfg, dirMgr *serverMgr.DiscoveryMgr) (result *GrpcLinker) {
	result = new(GrpcLinker)
	result.Info = info
	result.dirMgr = dirMgr
	result.lister, result.Port = sess.GetListener("tcp", info)
	result.GrpcServer = grpc.NewServer()
	messages.RegisterGrpcLinkerServer(result.GrpcServer, result)
	result.thgo = threads.NewThreadGo()
	return
}

func (this *GrpcLinker) Start() {
	this.thgo.Go(func(ctx context.Context) {
		_ = this.GrpcServer.Serve(this.lister)
	})
	logger.Info("GrpcLinker Start")
}

func (this *GrpcLinker) Stop() {
	logger.Info("GrpcLinker Stop")
	this.GrpcServer.GracefulStop()
}

// 路由消息到其他服务器
func (this *GrpcLinker) DoRouterSrvReq(ctx context.Context, req *messages.GrpcSrvReq) (ret *messages.GrpcSrvRet, err error) {
	logger.Debugf(logger.LogKey_Default, "DoRouterSrvReq OrderID:%d,MsgName:%s,ServerID:%d,PID:%d,SrvType:%d", req.OrderID, req.MsgName, req.ServerID, req.PID, req.SrvType)
	defer logger.Debugf(logger.LogKey_Default, "DoRouterSrvReq End OrderID:%d,MsgName:%s,ServerID:%d,PID:%d,SrvType:%d", req.OrderID, req.MsgName, req.ServerID, req.PID, req.SrvType)
	msg := new(protomsg.RouteMsgSrvReq)
	msg.MsgName = req.MsgName
	msg.MsgData = req.MsgData
	msg.OrderID = req.OrderID
	msg.Prefix = req.Prefix
	msg.SourceSrvID = global.GetCfgInst().GetServerID()
	msg.BackKey = global.GetSrvInst().GetNewEID()
	var srvid uint64
	if req.ServerID != 0 {
		//表示发给指定服务器
		srvid = req.ServerID
	} else if req.PID != 0 {
		//表示发给玩家，需要更新服务器类型来决定是否找路由
		msg.PID = req.PID
		switch req.SrvType {
		case global.ServerTypeClient:
			// 表示发给客户端
			if nttid, rderr := redisutil.NewGateSession(req.PID).GetEntityID(); rderr != nil {
				return nil, rderr
			} else {
				msg.EntityID = nttid
				srvid, msg.SpaceID, err = entity.NewRedisUtilEntity(nttid).
					GetSrvInfoByStype(req.SrvType)
				if err != nil {
					return nil, err
				}
			}
			/* 这里发给客户端的消息要怎么做？ */
			reqmsg, err := msgdef.GetTypeMgr().NewMsgByName(msg.MsgName, msg.MsgData)
			if err != nil {
				return nil, err
			}
			err = global.GetSrvInst().PostMsgToClient(srvid, msg.SpaceID, msg.EntityID, reqmsg)
			if err != nil {
				return nil, err
			}
			return &messages.GrpcSrvRet{MsgName: "", MsgData: nil, RetCode: 0}, nil
		case global.ServerTypeGateway, server.ServerType_Game:
			// 表示有状态服务器
			if nttid, rderr := redisutil.NewGateSession(req.PID).GetEntityID(); rderr != nil {
				return nil, rderr
			} else {
				msg.EntityID = nttid
				srvid, msg.SpaceID, err = entity.NewRedisUtilEntity(nttid).
					GetSrvInfoByStype(req.SrvType)
				if err != nil {
					return nil, err
				}
			}
		case global.GetCfgInst().GetSrvType():
			// 表示发给本服
			srvid = global.GetCfgInst().GetServerID()
		default:
			//其他服务器类型，一般就是无状态服务器
			if srvinfo, direrr := this.dirMgr.GetServerByType(global.GetCfgInst().GetGroupID(), req.SrvType); direrr != nil {
				return nil, direrr
			} else {
				srvid = srvinfo.GetServerID()
			}
		}
	} else if req.SrvType != 0 {
		//表示发给指定服务器类型，随便找一个服务器发消息过去处理就可以
		if srvinfo, direrr := this.dirMgr.GetServerByType(global.GetCfgInst().GetGroupID(), req.SrvType); direrr != nil {
			return nil, direrr
		} else {
			srvid = srvinfo.GetServerID()
		}
	} else {
		return nil, ErrGrpc_NoTarget
	}
	if msgret, msgerr := global.PostSrvSyncByRouteReq(srvid, msg); msgerr != nil {
		logger.Debugf(logger.LogKey_Default, " DoRouterSrvReq Error:%s", msgerr.Error())
		return nil, msgerr
	} else {
		ret = &messages.GrpcSrvRet{MsgName: msgret.MsgName, MsgData: msgret.MsgData, RetCode: msgret.RetCode}
		return ret, nil
	}

}
